溫馨提醒:這是教學用的簡化版,並非真實商品定價或醫療建議。實務需要大量統計資料、法規與精算檢核。
import csv
from math import pow
# 1) 基礎保費:按年齡帶(示意金額,單位:TWD/年)
AGE_BASE = [
    (18, 29, 6000),
    (30, 39, 7200),
    (40, 49, 9000),
    (50, 59, 12000),
    (60, 65, 16000)
]
# 2) BMI 分級與對應風險加成(僅示意)
#    例如 0.15 代表 +15%
BMI_BANDS = [
    ("體重過輕",  None, 18.5, 0.10),
    ("正常",      18.5, 24.0, 0.00),
    ("過重",      24.0, 27.0, 0.15),
    ("肥胖 I",    27.0, 30.0, 0.30),
    ("肥胖 II",   30.0, 35.0, 0.60),
    ("肥胖 III",  35.0, None, 1.00),
]
SMOKER_LOADING = 0.40  # 吸菸者 +40%(示意)
def bmi_value(height_cm: float, weight_kg: float) -> float:
    h_m = height_cm / 100.0
    return weight_kg / pow(h_m, 2)
def bmi_class_and_loading(bmi: float):
    for name, lo, hi, ld in BMI_BANDS:
        if (lo is None or bmi >= lo) and (hi is None or bmi < hi):
            return name, ld
    return "未定義", 0.0
def base_premium_by_age(age: int) -> int:
    for lo, hi, base in AGE_BASE:
        if lo <= age <= hi:
            return base
    # 若超出範圍,給予簡單外推(示意)
    if age < AGE_BASE[0][0]:
        return AGE_BASE[0][2]
    return int(AGE_BASE[-1][2] * 1.3)
def quote_premium(profile: dict):
    age = profile["age"]
    h = profile["height_cm"]
    w = profile["weight_kg"]
    smoker = profile.get("smoker", False)
    bmi = round(bmi_value(h, w), 1)
    bmi_cls, bmi_ld = bmi_class_and_loading(bmi)
    base = base_premium_by_age(age)
    total_loading = bmi_ld + (SMOKER_LOADING if smoker else 0.0)
    premium = round(base * (1 + total_loading))
    breakdown = {
        "name": profile.get("name", ""),
        "age": age,
        "height_cm": h,
        "weight_kg": w,
        "smoker": "是" if smoker else "否",
        "BMI": bmi,
        "BMI分級": bmi_cls,
        "基礎保費": base,
        "風險加成(%)": f"{int(total_loading*100)}%",
        "年保費_估": premium
    }
    return breakdown
# 3) 測試三位被保人(你可以自行修改)
people = [
    {"name": "Alice", "age": 29, "height_cm": 165, "weight_kg": 56, "smoker": False},  # 正常
    {"name": "Bob",   "age": 43, "height_cm": 175, "weight_kg": 88, "smoker": False},  # 過重/肥胖I邊緣
    {"name": "Carol", "age": 37, "height_cm": 160, "weight_kg": 95, "smoker": True},   # 肥胖II + 吸菸
]
rows = [quote_premium(p) for p in people]
# 列印結果
print("=== BMI 保費模擬(示意)===")
for r in rows:
    print(f"{r['name']:>5}|年齡:{r['age']:>2} |BMI:{r['BMI']:>4}({r['BMI分級']})"
          f"|基礎保費:{r['基礎保費']:>6}|加成:{r['風險加成(%)']:>4}|估算年保費:{r['年保費_估']:>6}|吸菸:{r['smoker']}")
# 4) 輸出 CSV,方便後續視覺化或做報告
with open("premium_quote.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=list(rows[0].keys()))
    writer.writeheader()
    writer.writerows(rows)
print("\n✅ 已輸出報價列表:premium_quote.csv")